package org.example.core;

import java.io.IOException;
import java.io.RandomAccessFile;

/**
 * 磁盘模拟器 - 使用文件模拟磁盘块
 */
public class DiskEmulator {
    private static final int BLOCK_SIZE = 64;     // 每个块64字节
    private static final int BLOCK_COUNT = 128;   // 总共128个块

    private RandomAccessFile diskFile; // 磁盘文件句柄，用于读写磁盘块
    private String diskFileName; // 磁盘文件名，用于存储模拟的磁盘数据

    public DiskEmulator(String fileName) throws IOException {
        this.diskFileName = fileName;
        initializeDisk();
    }

    /**
     * 初始化磁盘文件
     * @throws IOException
     */
    private void initializeDisk() throws IOException {
        diskFile = new RandomAccessFile(diskFileName, "rw"); // 以读写模式打开文件

        // 如果文件不存在或为空，初始化为指定大小
        if (diskFile.length() == 0) {
            diskFile.setLength(BLOCK_SIZE * BLOCK_COUNT); // 初始化文件大小为128个块
            System.out.println("创建新的磁盘文件: " + diskFileName);
        } else {
            System.out.println("加载现有磁盘文件: " + diskFileName);
        }
    }

    /**
     * 读取指定磁盘块
     * @param blockNum 要读取的块号，必须在 0 到 127 之间
     * @return 包含块数据的字节数组，大小为 64 字节
     * @throws IOException 如果发生 I/O 错误
     */
    public byte[] readBlock(int blockNum) throws IOException {
        validateBlockNumber(blockNum); // 验证块号是否有效，确保在有效范围内

        byte[] block = new byte[BLOCK_SIZE]; // 创建一个字节数组，用于存储读取的块数据
        diskFile.seek(blockNum * BLOCK_SIZE); // 移动文件指针到指定块的起始位置
        diskFile.readFully(block); // 读取指定数量的字节到字节数组中
        return block;
    }

    /**
     * 写入指定磁盘块
     * @param blockNum 要写入的块号，必须在 0 到 127 之间
     * @param data 要写入的字节数组，大小必须为 64 字节
     * @throws IOException 如果发生 I/O 错误
     */
    public void writeBlock(int blockNum, byte[] data) throws IOException {
        validateBlockNumber(blockNum);

        if (data.length != BLOCK_SIZE) { // 验证数据大小是否正确
            throw new IllegalArgumentException("数据大小必须为 " + BLOCK_SIZE + " 字节");
        }

        diskFile.seek(blockNum * BLOCK_SIZE);
        diskFile.write(data);
    }

    private void validateBlockNumber(int blockNum) {
        if (blockNum < 0 || blockNum >= BLOCK_COUNT) {
            throw new IllegalArgumentException("块号必须在 0 到 " + (BLOCK_COUNT-1) + " 之间");
        }
    }

    public void close() throws IOException {
        if (diskFile != null) {
            diskFile.close();
            System.out.println("磁盘文件已关闭");
        }
    }

    public int getBlockSize() {
        return BLOCK_SIZE;
    }

    public int getBlockCount() {
        return BLOCK_COUNT;
    }


}